package com.sg.common;

import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TimeZone;

/**
 * bean类型转换
 *
 * @author Administrator
 * @date 2022/8/24
 */
@Slf4j
public class BeanConvertUtil {

    private BeanConvertUtil() {
    }

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
            .setDateFormat(new SimpleDateFormat(DateFormatConsts.DATETIME_FORMAT))
            .setTimeZone(TimeZone.getTimeZone("GMT+8"))
            // 忽略json字符串中不识别的属性
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            // jdk8时间类型
            .registerModule(new JavaTimeModule()
                    .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DateFormatConsts.DATETIME_FORMAT)))
                    .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DateFormatConsts.DATE_FORMAT)))
                    .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DateFormatConsts.TIME_FORMAT)))
                    .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DateFormatConsts.DATETIME_FORMAT)))
                    .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DateFormatConsts.DATE_FORMAT)))
                    .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DateFormatConsts.TIME_FORMAT)))
            )
            .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);

    /**
     * 单个bean类型转换，使用json方式
     *
     * @param sourceObj   需要转换的源object
     * @param targetClass 转换成的目标Class
     * @param <T>         转换成的目标Class
     * @return targetObj-转换成功的目标object
     */
    public static <T> T convertByJson(Object sourceObj, Class<T> targetClass) {
        if (sourceObj == null || targetClass == null) {
            return null;
        }
        T targetObj = null;
        Class<?> sourceObjClass = sourceObj.getClass();
        Field[] sourceObjClassDeclaredFields = sourceObjClass.getDeclaredFields();
        // 是否包含枚举字段
        boolean includeEnum = false;
        for (Field sourceField : sourceObjClassDeclaredFields) {
            if (sourceField.getType().isEnum()) {
                includeEnum = true;
                break;
            }
        }
        try {
            String sourceJson;
            if (includeEnum) {
                sourceJson = JSONObject.toJSONString(sourceObj);
            } else {
                sourceJson = OBJECT_MAPPER.writeValueAsString(sourceObj);
            }
            targetObj = OBJECT_MAPPER.readValue(sourceJson, targetClass);
        } catch (JsonProcessingException e) {
            log.error("sourceObj:{},targetClass:{}类型转换异常：{}", sourceObj, targetClass, e);
        }
        return targetObj;
    }

    /**
     * List类型转换，使用json方式
     *
     * @param sourceList  需要转换的源list
     * @param targetClass 转换成的目标Class
     * @param <T>         转换成的目标Class
     * @return targetList-转换成功的目标list
     */
    public static <T> List<T> convertListByJson(List<?> sourceList, Class<T> targetClass) {
        if (CollectionUtils.isEmpty(sourceList) || targetClass == null) {
            return Collections.emptyList();
        }
        List<T> targetList = new ArrayList<>();
        sourceList.forEach(sourceObj -> targetList.add(convertByJson(sourceObj, targetClass)));
        return targetList;
    }

    /**
     * 单个bean类型转换
     *
     * @param sourceObj   需要转换的源object
     * @param targetClass 转换成的目标Class
     * @param <T>         转换成的目标Class
     * @return targetObj-转换成功的目标object
     */
    public static <T> T convert(Object sourceObj, Class<T> targetClass) {
        if (sourceObj == null || targetClass == null) {
            return null;
        }
        T targetObj = null;
        try {
            targetObj = targetClass.getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(sourceObj, targetObj);
        } catch (Exception e) {
            log.error("sourceObj:{},targetClass:{}类型转换异常：{}", sourceObj, targetClass, e);
        }
        return targetObj;
    }

    /**
     * List类型转换
     *
     * @param sourceList  需要转换的源list
     * @param targetClass 转换成的目标Class
     * @param <T>         转换成的目标Class
     * @return targetList-转换成功的目标list
     */
    public static <T> List<T> convertList(List<?> sourceList, Class<T> targetClass) {
        if (CollectionUtils.isEmpty(sourceList) || targetClass == null) {
            return Collections.emptyList();
        }
        List<T> targetList = new ArrayList<>();
        sourceList.forEach(sourceObj -> targetList.add(convert(sourceObj, targetClass)));
        return targetList;
    }


}
